Docker, Kubernetes, DCOS 不谈信仰谈技术
看来容器编排系统的争夺已经白热化了,乱花渐欲迷人眼,最近老是有各种文章比较这三个框架,这篇文章不谈信仰,不对比优劣,只谈技术,甚至会谈如果从一个平台转向另一个平台,都要了解些啥。
一、架构
啥都不说,先上三个架构图
Docker Swarm Mode
DCOS
这张图主要显示了一些组件,还是上一张Mesos的图
最后是Kubernetes
这三个架构都很复杂,但是还是能够一眼看出是一个老大,多个干活的这种结构,基本上所有的分布式系统都是这样,但是里面的组件名称就纷繁复杂,我们来一一解析。
二、元数据存储与集群维护
作为一个集群系统,总要有一个统一的地方维护整个集群以及任务的元数据。而且作为集群系统的控制节点,为了高可用性,往往存在多个Master,在多个Master中间,总要有一个Leader。
在Docker Swarm Mode里面,多个Manager之间需要选出一个Leader,而且整个集群的状态也需要在一个统一的地方存储,从而任何一个Manager挂了之后,其他的Manager能够马上接替上,Swarm Node通过Raft协议,自己实现了一个内部的统一存储和集群一致性管理系统。在传统的Swarm里面,推荐的使用consul,在Swarm Mode里面则自己实现了。
在docker swarm init的参数里面有--advertise-addr声明swarm manager会通过这个地址和端口让其他组件来连接。
在DCOS里面,Mesos的多个进程也需要选择一个Leader,容器的编排多通过Marathon进行,Marathon需要一个地方存储所有Task的信息,在DCOS里面,多通过Zookeeper来实现。
在Mesos Master的启动有参数--zk=VALUE。
当然也能看到熟悉的--advertise_ip=VALUE和--advertise_port=VALUE。
Marathon启动的时候,也有参数--zk zk://1.2.3.4:2181,2.3.4.5:2181,3.4.5.6:2181/marathon。
在Kubernetes里面,统一的存储使用etcd来保存,Leader的选举也是通过etcd进行,因而有apiserver有参数--etcd-servers,controller和scheduler都有参数--master string指向apiserver,并且有参数--leader-elect选举出Leader,也会有熟悉的--address ip。
三、API层与命令行
作为一个分布式系统,每一层都会有自己的API,但是对外往往需要一个统一的API接口层,一般除了酷酷的界面之外,为了自动化,往往会有一个命令行可以执行操作,其实命令里面封装的也是对API的调用。
对于Docker Swarm Mode来讲,API层是集成在Manager里面的,而命令行其实就是Docker的命令行,只不过调用的时候,原来是Docker Daemon本地把事情做了,现在Manager需要让Work去做事情。
这一点也是Docker的优势所在,也即使用本地的Docker和使用Swarm Mode集群,不需要学习成本,一样的命令,同样的味道。
对于DCOS来讲,API层是有一个单独的组件,叫做Admin Router,后端的很多API都是通过Admin Router经过封装暴露给外面的。
对于命令行,有一个dcos cli,可以调用admin router暴露出来的api进行操作。
dcos命令行可以有一些子命令,例如marathon子命令,就是用来创建容器的,node可以管理节点。
dcos里面很有特色的一点就是可以安装package,这源于mesos是一个双层调度系统,上面可以跑多个framework,例如spark,cassandra等,都可以通过package进行安装,这点会另外一节说明。
对于Kubernetes,API层是一个单独的进程apiserver提供,认证和鉴权也是在这一层实现的,所有对于kubernetes的管理平台的访问都是通过apiserver这一层进行的。
对于命令行,kubernetes是kubectl,通过向apiserver调用执行操作,例如pod,service,deployment等。
kubernetes也有自己的类似package的管理,Kubernetes Helm,但是命令就变成了helm了。
四、调度
当运行一个容器的时候,放在哪台节点上,这个过程是调度。
Swarm Mode 的调度的默认规则是spread,也即尽量让容器平均分配到整个集群当中。
当然也可以设置一些调度策略,例如使用constraint,每个节点可以配置一些label,并在创建容器的时候通过指定constraint,来使得容器运行或者不运行在某些节点上。
docker node update --label-add 'com.acme.server=db' node-03
docker service create --name redis --constraint 'node.labels.com.acme.server==db' redis
也可以使用placement-pref,使得容器优先调度在某些节点上。
docker service create --name nginx --placement-pref 'spread=node.labels.com.acme.zone' --replicas 12 nginx
对于DCOS来讲,Mesos的调度是双层调度,首先一层是Mesos Master的Allocator将节点资源提供给框架,例如Marathon,第二层是Marathon里面也有一个调度器,真正分配某个容器放在某个节点上。
Mesos的调度策略参考文章号称了解mesos双层调度的你,先来回答下面这五个问题!
Marathon的调度也可以有constraints。
"constraints": [["hostname", "UNIQUE"]]表示每个节点只能跑一个。
"constraints": [["rack_id", "CLUSTER", "rack-1"]]容器跑着有attribute为rack_id并且值为rack-1的节点上。
"constraints": [["rack_id", "GROUP_BY", "3"]]将容器分布在三个rack上以实现高可用。
"constraints": [["rack_id", "LIKE", "rack-[1-3]"]]和"constraints": [["rack_id", "UNLIKE", "rack-[7-9]"]]表示容器要跑在哪些节点上和不能跑在哪些节点上。
"constraints": [["rack_id", "MAX_PER", "2"]]表示每个rack最多能跑两个容器。
对于Kubernetes,调度是由一个单独的进程scheduler负责的。
Kubernetes也支持通过对Node设置Label,从而将pod放在某些节点上。
kubectl label nodes <your-node-name> disktype=ssd
apiVersion: v1kind: Podmetadata:
name: nginx
labels:
env: testspec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
另外kubernetes还有NodeAffinity:
RequiredDuringSchedulingRequiredDuringExecution:在调度的时候必须部署到某些节点,运行期如果条件不满足则重新调度
RequiredDuringSchedulingIgnoredDuringExecution :在调度的时候必须部署到某些节点,运行期就算了。
PreferredDuringSchedulingIgnoredDuringExecution :在调度的时候最好部署到某些节点,运行期就算了。
五、副本与弹性伸缩
容器如果部署无状态服务,一个好处就是可以多副本,并且可以弹性伸缩。
在Swarm Mode里面,可以通过scale数字指定副本数目。
docker service scale frontend=50
在DCOS里面,通过instances指定副本的数目。
{
"id": "nginx",
"container": {
"type": "DOCKER",
"docker": {
"image": "mesosphere/simple-docker",
"network": "BRIDGE",
"portMappings": [
{ "hostPort": 80, "containerPort": 80, "protocol": "tcp"}
]
}
},
"acceptedResourceRoles": ["slave_public"],
"instances": 1,
"cpus": 0.1,
"mem": 64
}
修改数目的时候使用以下的命令
dcos marathon app update basic-0 instances=6
在最新版本的DCOS中,已经支持的pod的概念了。
{
"containers": [
{
"artifacts": [],
"endpoints": [],
"environment": {},
"exec": {
"command": {
"shell": "sleep 1000"
}
},
"healthCheck": null,
"image": null,
"labels": {},
"lifecycle": null,
"name": "sleep1",
"resources": {
"cpus": 0.1,
"disk": 0,
"gpus": 0,
"mem": 32
},
"user": null,
"volumeMounts": []
}
],
"environment": {},
"id": "/simplepod2",
"labels": {},
"networks": [
{
"labels": {},
"mode": "host",
"name": null
}
],
"scaling": {
"instances": 2,
"kind": "fixed",
"maxInstances": null
},
"scheduling": {
"backoff": {
"backoff": 1,
"backoffFactor": 1.15,
"maxLaunchDelay": 3600
},
"placement": {
"acceptedResourceRoles": [],
"constraints": []
},
"upgrade": {
"maximumOverCapacity": 1,
"minimumHealthCapacity": 1
}
},
"secrets": {},
"user": null,
"volumes": []
}
在DCOS里面可以实现自动弹性伸缩,通过使用marathon-lb-autoscale,通过监控marathon-lb的情况进行弹性伸缩。
在Kubernetes里面,副本数目是以pod为单位的,由controller进程控制,可以通过创建一个Deployment来控制副本数。
apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Kubernetes也可以实现autoscaling。
有一个组件Horizontal Pod Autoscaling,可以通过监控CPU的使用情况动态调整Pod的数量。
六、编排
为了能够通过编排文件一键创建整个应用,需要有编排功能。
Swarm Mode的编排
docker stack deploy --compose-file docker-compose.yml vossibility
version: "2"
services:
foo:
image: foo
volumes_from: ["bar"]
network_mode: "service:baz"
environment:
- "constraint:node==node-1"
bar:
image: bar
environment:
- "constraint:node==node-1"
baz:
image: baz
environment:
- "constraint:node==node-1"
Marathon的编排是基于json文件
{
"id": "/product",
"groups": [
{
"id": "/product/database",
"apps": [
{ "id": "/product/database/mongo", ... },
{ "id": "/product/database/mysql", ... }
]
},{
"id": "/product/service",
"dependencies": ["/product/database"],
"apps": [
{ "id": "/product/service/rails-app", ... },
{ "id": "/product/service/play-app", ... }
]
}
]
}
Kubernetes的编排是基于yml文件
为redis-master服务新建一个名为redis-master-controller.yaml的RC定义文件
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: kubeguide/redis-master
ports:
- containerPort: 6379
创建一个Service
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
name: redis-master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
name: redis-master
七、服务发现与DNS
容器平台的一个重要的功能是服务发现,也即当容器的地址改变的时候,可以自动进行服务之间的关联。
一般的服务发现首先要通过DNS将服务名和应用关联起来,可以基于DNS对一个服务的多个应用进行内部负载均衡,也有直接加一个内部负载均衡器来做这件事情。
Swarm Mode有一个内置的DNS组件,并且负载均衡也是根据DNS名来做的。
DCOS的DNS组件是通过Mesos-DNS实现的,负载均衡有两种方式,一种是直接通过Mesos-DNS根据域名进行负载均衡。另一种方式是将DNS转化为VIP,然后有个内置的负载均衡器,DCOS有个组件minuteman是做这个事情的。
Kubernetes的DNS组件是通过skyDNS实现的,负载均衡是通过将DNS转化为VIP,有个内置的负载均衡器kube-proxy来完成这件事情。
八、容器
Swarm Mode通过runC运行容器
DCOS对于多种容器的支持Unified Container,可以支持Docker容器和Mesos容器。
Kubernetes也是支持多种容器格式的。
九、网络
容器的网络配置两种:
Docker Libnetwork Container Network Model(CNM)阵营
● Docker Swarm overlay
● Macvlan & IP network drivers
● Calico
● Contiv(from Cisco)
Docker Libnetwork的优势就是原生,而且和Docker容器生命周期结合紧密;缺点也可以理解为是原生,被Docker“绑架”。
Container Network Interface(CNI)阵营
● Kubernetes
● Weave
● Macvlan
● Flannel
● Calico
● Contiv
● Mesos CNI
CNI的优势是兼容其他容器技术(e.g. rkt)及上层编排系统(Kuberneres & Mesos),而且社区活跃势头迅猛,缺点是非Docker原生。
十、存储
Swarm Mode的存储是通过Volume Plugin,可以在集群中接入外部的统一存储,可以支持Ceph,NFS,GlusterFS等。
DCOS可以创建External Persistent Volumes,dvdi driver其实使用的也是Docker的volume driver,目前支持的是rexray,可以接入EC2,OpenStack等。
Kubernetes可以创建Persistent Volumes,支持GCE,AWS,NFS,GlusterFS,Ceph等。
十一、监控
无论是Swarm Mode,还是Mesos,还是Kubernetes,容器的监控中Prometheus +cadvisor都是主流的方案,而cadvisor来自Kubernetes的一个组件。
十二、大数据与包管理
跑大数据是Mesos的强项,Spark就有一个依赖于Mesos部署,让Mesos作为调度器的方案。
对于Swarm Mode和Kubernetes来讲,不会用自己的Scheduler来做大数据调用。
但是Swarm Mode和Kubernetes是可以部署大数据框架的,但是大数据框架之间的任务的调度和通信,就与Swarm Mode和Kubernetes无关了。
在kubernetes里面部署大数据可以参考https://github.com/kubernetes/examples
十三、负载均衡
这里的负载均衡指的是外部负载均衡。
在Swarm Mode中,swarm manager通过ingress负载均衡,通过published port将服务端口暴露在Node上面,如果有外部云平台的负载均衡器,通过连接Node上的端口,可以对服务进行外部负载均衡。
在DCOS中,外部负载均衡通过marathon-lb来实现。
在kubernetes中,外部负载均衡器是通过一个ingress controller根据请求进行创建,如果在云平台例如GCE,可创建云平台的负载均衡器,云平台的负载均衡器可通过NodePort连接到后端的Service。
https://github.com/kubernetes/ingress
可以通过service连接后端的Pod.
也可以不用service直接连接。
十四、节点
Swarm Mode的Node上面部署的是Swarm的worker,其实还是Docker Daemon,相对保持一致性。
DCOS的Node上面干活的是Mesos-Agent,其实它还不是直接干活的,还有一层Executor真正的干活。
kubernetes的Node上跑的是kubelet。
十五、升级与回滚
所有的容器平台对于容器多副本的升级全部都是要滚动升级。
在Swarm Node里面可以配置rolling update策略
docker service create --name=my_redis \
--replicas=5 \
--rollback-parallelism=2 \
--rollback-monitor=20s \
--rollback-max-failure-ratio=.2 \
redis:latest
在DCOS里面,rolling update也是默认的行为。
在Kubernetes里面,同样有对rolling update的支持。
kubectl rolling-update foo [foo-v2] --image=myimage:v2
总而言之:三大平台的区别,大概相当于麦当劳和肯德基的区别,看你的口味,掌控能力,社区热度了。